<!DOCTYPE html>
<title>CSS Values and Units Test: attr</title>
<meta name="assert" content="test attr values">
<link rel="help" href="https://drafts.csswg.org/css-values-5/#attr-notations">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<html>
  <body>
    <div id="attr"></div>
    <div id="expected"></div>
  </body>
</html>

<script>
    const dimensionTypeToUnits = {
        "length": ["em", "ex", "cap", "ch", "ic", "rem", "lh", "rlh", "vw", "vh ", "vi", "vb", "vmin", "vmax"],
        "angle": ["deg", "grad", "rad", "turn"],
        "time": ["ms", "ms"],
        "frequency": ["Hz", "kHz"],
        "flex": ["fr"]
    };
    const dimensionTypeToProperty = {
        "length": ["width"],
        "angle": ["font-style"],
        "time": ["transition-duration"],
        "flex": ["grid-template-columns"]
    }

    function test_valid_attr(property, attrString, attrValue, expectedValue) {
        var elem = document.getElementById("attr");
        elem.setAttribute("data-foo", attrValue);
        elem.style[property]= attrString;

        var expectedElem =  document.getElementById("expected");
        expectedElem.style[property] = expectedValue;

        test(() => {
            assert_equals(window.getComputedStyle(elem).getPropertyValue(property),
                          window.getComputedStyle(expectedElem).getPropertyValue(property),
                          "Value \'" + attrString + "\', where \'data-foo=" + attrValue +
                          "\' should be valid for the property \'" + property + "\'.");
        });

        elem.style[property] = null;
        expectedElem.style[property] = null;
    }

    function test_invalid_attr(property, attrString, attrValue) {
        var elem = document.getElementById("attr");
        var expectedValue = window.getComputedStyle(elem).getPropertyValue(property);

        elem.setAttribute("data-foo", attrValue);
        elem.style[property]= attrString;

        test(() => {
            assert_equals(window.getComputedStyle(elem).getPropertyValue(property), expectedValue,
                          "Setting property \'" + property + "\' to the value \'" + attrString +
                          "\', where \'data-foo=" + attrValue + "\' should not change it's value.");
        });
        elem.style[property] = null;
    }

    function test_dimension_types_and_units() {
        for(const [type, units] of Object.entries(dimensionTypeToUnits)) {
            const property = dimensionTypeToProperty[type];
            const val = "3";
            units.forEach(unit => {
                const expectedValue = val + unit;

                const dimensionTypeAttrString = 'attr(data-foo ' + type + ')';
                test_valid_attr(property, dimensionTypeAttrString, expectedValue, expectedValue);

                const dimensionUnitAttrString = 'attr(data-foo ' + unit + ')';
                test_valid_attr(property, dimensionUnitAttrString, val, expectedValue);
            });
        }
    }

    test_valid_attr('content', 'attr(data-foo string)', 'abc', '"abc"');
    test_valid_attr('content', 'attr(data-foo string)', 'attr(data-foo)', '"attr(data-foo)"');

    test_valid_attr('animation-name', 'attr(data-foo ident)', 'anim', 'anim');
    test_valid_attr('animation-name', 'attr(data-foo ident, anim-fallback)', '"anim"', 'anim-fallback');
    test_valid_attr('animation-name', 'attr(data-foo ident, anim-fallback)', 'initial', 'anim-fallback');

    test_valid_attr('background-color', 'attr(data-foo color)', 'red', 'red');
    test_valid_attr('background-color', 'attr(data-foo color)', '#ff0099aa', '#ff0099aa');
    test_valid_attr('background-color', 'attr(data-foo color, red)', '10', 'red');
    test_valid_attr('background-color', 'attr(data-foo color, green)', '1000px', 'green');
    test_valid_attr('background-color', 'attr(data-foo color, green)', 'rgb(255, 0, 0)', 'green');

    test_valid_attr('font-weight', 'attr(data-foo number)', '10', '10');
    test_valid_attr('font-weight', 'attr(data-foo number, 30)', '10px', '30');
    test_valid_attr('font-weight', 'attr(data-foo number, calc(10 + 20))', '10px', '30');

    test_valid_attr('font-size', 'attr(data-foo percentage)', '10%', '10%');
    test_valid_attr('font-size', 'attr(data-foo percentage, 10px)', 'abc', '10px');
    test_valid_attr('--x', 'attr(data-foo percentage, abc)', '10', 'abc');

    test_valid_attr('width', 'attr(data-foo length)', '10px', '10px');
    test_valid_attr('width', 'attr(data-foo length, red)', '10px', '10px');
    test_valid_attr('width', 'attr(data-foo length, 42px)', 'calc(1px + 3px)', '42px');

    test_valid_attr('font-style', 'attr(data-foo angle)', '10deg', '10deg');
    test_valid_attr('font-style', 'attr(data-foo angle, 10deg)', '30', '10deg');
    test_valid_attr('font-style', 'attr(data-foo angle, italic)', '30', 'italic');

    test_valid_attr('transition-duration', 'attr(data-foo time)', '10ms', '10ms');
    test_valid_attr('transition-duration', 'attr(data-foo time, 30s)', '10m', '30s');
    test_valid_attr('transition-duration', 'attr(data-foo time, calc(10s + 20s))', '10m', '30s');

    test_valid_attr('grid-template-columns', '30px attr(data-foo flex)', '1fr', '30px 1fr');
    test_valid_attr('grid-template-columns', 'attr(data-foo flex, 3fr)', '1fr 1fr', '3fr');
    test_valid_attr('grid-template-columns', 'attr(data-foo flex, calc(1px + 2px))', '10px', '3px');

    test_valid_attr('height', 'attr(data-foo px)', '10', '10px');
    test_valid_attr('width', 'calc(attr(data-foo px) + 1px)', '10', '11px');
    test_valid_attr('--x', 'attr(data-foo px) 11px', '10', '10px 11px');
    test_valid_attr('grid-template-columns', 'attr(data-foo fr)', '10', '10fr');
    test_valid_attr('grid-template-columns', 'attr(data-foo fr, 3fr)', '10fr', '3fr');

    test_dimension_types_and_units();

    test_invalid_attr('animation-name', 'attr(data-foo ident)', 'initial');
    test_invalid_attr('animation-name', 'attr(data-foo ident)', '"anim"');
    test_invalid_attr('animation-name', 'attr(data-foo ident)', '"none"');

    test_invalid_attr('background-color', 'attr(data-foo color)', 'rgb(0 255 0)');
    test_invalid_attr('background-color', 'attr(data-foo color)', 'color-mix(in lch, red, pink)');
    test_invalid_attr('background-color', 'attr(data-foo color)', 'light-dark(#333b3c, #efefec)');
    test_invalid_attr('background-color', 'attr(data-foo red)', 'abc');
    test_invalid_attr('background-color', 'attr(data-foo, red)', 'abc');

    test_invalid_attr('font-size', 'attr(data-foo number)', '10');
    test_invalid_attr('font-weight', 'attr(data-foo number,)', '10');
    test_invalid_attr('font-weight', 'attr(data-foo number)', 'calc(1 + 3)');

    test_invalid_attr('font-size', 'attr(data-foo percentage)', 'abc');
    test_invalid_attr('font-size', 'attr(data-foo percentage)', '10% a');
    test_invalid_attr('font-size', 'attr(data-foo percentage, 10rad)', 'abc');

    test_invalid_attr('width', 'attr(data-foo length)', '10');
    test_invalid_attr('width', 'attr(data-foo length, 30)', 'calc(10 + 20)');
    test_invalid_attr('width', 'attr(data-foo length, calc(10 + 20))', 'abc');

    test_invalid_attr('font-style', 'attr(data-foo angle)', '10%');
    test_invalid_attr('font-style', 'attr(data-foo angle)', 'calc(10px + 20px)');
    test_invalid_attr('font-style', 'attr(data-foo angle, calc(10 + 20))', 'calc(10px + 20px)');

    test_invalid_attr('transition-duration', 'attr(data-foo time)', '10');
    test_invalid_attr('transition-duration', 'attr(data-foo time)', '10 ms');
    test_invalid_attr('transition-duration', 'attr(data-foo time)', 'calc(1ms + 2ms)s');

    test_invalid_attr('grid-template-columns', 'attr(data-foo flex)', '10px');
    test_invalid_attr('grid-template-columns', 'attr(data-foo flex)', '"30fr"');
    test_invalid_attr('grid-template-columns', 'attr(data-foo flex, calc(1deg + 2deg))', '10px');

    test_invalid_attr('width', 'attr(data-foo px)', '10px');
    test_invalid_attr('height', 'attr(data-foo fr)', '10');
    test_invalid_attr('transition-duration', 'attr(data-foo ms)', '10px');
    test_invalid_attr('transition-duration', 'attr(data-foo ms)', '10px foo');
</script>